--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit aaa450fe281407a4bb23b65b95844efe02f2c603
Parents : a022a96
Author : Sudo-Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-01-14T17:56:29-06:00
Add Reticulum config validation and default creation
- Implemented a method to ensure a valid Reticulum config file exists, creating a default if missing or invalid.
- Better error handling for reading and writing the config file to improve robustness during initialization.
Changes
Diff
diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py
index 01c54b42..40648ab4 100644
--- a/meshchatx/meshchat.py
+++ b/meshchatx/meshchat.py
@@ -556,6 +556,152 @@ class ReticulumMeshChat:
raise RuntimeError("Database not initialized")
return self.database.restore_database(backup_path)
+ def _ensure_reticulum_config(self):
+ """Ensures that a valid Reticulum config file exists at the expected location.
+ If the config is missing or invalid, it creates a sane default one.
+ """
+ config_dir = self.reticulum_config_dir or RNS.Reticulum.configpath
+ config_file = os.path.join(config_dir, "config")
+
+ should_recreate = False
+
+ if not os.path.exists(config_file):
+ should_recreate = True
+ print(
+ f"Reticulum config file not found at {config_file}, creating a default one...",
+ )
+ else:
+ try:
+ with open(config_file) as f:
+ content = f.read()
+ if "[reticulum]" not in content or "[interfaces]" not in content:
+ print(
+ f"Reticulum config file at {config_file} is invalid (missing essential sections), recreating...",
+ )
+ should_recreate = True
+ except Exception as e:
+ print(
+ f"Failed to read Reticulum config at {config_file} ({e}), recreating...",
+ )
+ should_recreate = True
+
+ if should_recreate:
+ try:
+ if not os.path.exists(config_dir):
+ os.makedirs(config_dir, exist_ok=True)
+
+ default_config = """# This is the default Reticulum config file.
+# You should probably edit it to include any additional,
+# interfaces and settings you might need.
+
+# Only the most basic options are included in this default
+# configuration. To see a more verbose, and much longer,
+# configuration example, you can run the command:
+# rnsd --exampleconfig
+
+
+[reticulum]
+
+ # If you enable Transport, your system will route traffic
+ # for other peers, pass announces and serve path requests.
+ # This should only be done for systems that are suited to
+ # act as transport nodes, ie. if they are stationary and
+ # always-on. This directive is optional and can be removed
+ # for brevity.
+
+ enable_transport = False
+
+
+ # By default, the first program to launch the Reticulum
+ # Network Stack will create a shared instance, that other
+ # programs can communicate with. Only the shared instance
+ # opens all the configured interfaces directly, and other
+ # local programs communicate with the shared instance over
+ # a local socket. This is completely transparent to the
+ # user, and should generally be turned on. This directive
+ # is optional and can be removed for brevity.
+
+ share_instance = Yes
+
+
+ # If you want to run multiple *different* shared instances
+ # on the same system, you will need to specify different
+ # instance names for each. On platforms supporting domain
+ # sockets, this can be done with the instance_name option:
+
+ instance_name = default
+ discover_interfaces = True
+ autoconnect_discovered_interfaces = 3
+ required_discovery_value = 16
+
+# Some platforms don't support domain sockets, and if that
+# is the case, you can isolate different instances by
+# specifying a unique set of ports for each:
+
+# shared_instance_port = 37428
+# instance_control_port = 37429
+
+
+# If you want to explicitly use TCP for shared instance
+# communication, instead of domain sockets, this is also
+# possible, by using the following option:
+
+# shared_instance_type = tcp
+
+
+# You can configure Reticulum to panic and forcibly close
+# if an unrecoverable interface error occurs, such as the
+# hardware device for an interface disappearing. This is
+# an optional directive, and can be left out for brevity.
+# This behaviour is disabled by default.
+
+# panic_on_interface_error = No
+
+
+[logging]
+ # Valid log levels are 0 through 7:
+ # 0: Log only critical information
+ # 1: Log errors and lower log levels
+ # 2: Log warnings and lower log levels
+ # 3: Log notices and lower log levels
+ # 4: Log info and lower (this is the default)
+ # 5: Verbose logging
+ # 6: Debug logging
+ # 7: Extreme logging
+
+ loglevel = 4
+
+
+# The interfaces section defines the physical and virtual
+# interfaces Reticulum will use to communicate on. This
+# section will contain examples for a variety of interface
+# types. You can modify these or use them as a basis for
+# your own config, or simply remove the unused ones.
+
+[interfaces]
+
+ # This interface enables communication with other
+ # link-local Reticulum nodes over UDP. It does not
+ # need any functional IP infrastructure like routers
+ # or DHCP servers, but will require that at least link-
+ # local IPv6 is enabled in your operating system, which
+ # should be enabled by default in almost any OS. See
+ # the Reticulum Manual for more configuration options.
+
+ [[Default Interface]]
+ type = AutoInterface
+ enabled = false
+ name = Default Interface
+ selected_interface_mode = 1
+"""
+ with open(config_file, "w") as f:
+ f.write(default_config)
+ print(f"Default Reticulum config created at {config_file}")
+ except Exception as e:
+ print(
+ f"Failed to create default Reticulum config at {config_file}: {e}",
+ )
+
def setup_identity(self, identity: RNS.Identity):
identity_hash = identity.hash.hex()
@@ -574,6 +720,7 @@ class ReticulumMeshChat:
# Initialize Reticulum if not already done
if not hasattr(self, "reticulum"):
+ self._ensure_reticulum_config()
self.reticulum = RNS.Reticulum(self.reticulum_config_dir)
# Create new context
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────